package com.loe.ktui.custom

import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import androidx.core.content.res.getResourceIdOrThrow
import androidx.core.view.forEach
import androidx.viewpager.widget.ViewPager
import com.loe.ktui.*
import com.loe.ktui.KtViewPager
import com.loe.ktui.UiGroup
import com.loe.ktui.UiView
import com.loe.ktui.util.UiShape

open class UiTab(id: String? = null) : UiGroup(id)
{
    override var width: Any? = MATCH_PARENT

    var divider: Any? = null
    var showDividers: Int? = null

    var onItemSelect: (KtTabView.(view: View, isSelect: Boolean, i: Int, bean: Any) -> Unit)? = null
    fun onItemSelect(onItemSelect: KtTabView.(view: View, isSelect: Boolean, i: Int, bean: Any) -> Unit)
    {
        this.onItemSelect = onItemSelect
    }

    var itemConvert: (KtTabView.(view: View, i: Int, bean: Any) -> Unit)? = null
    fun itemConvert(itemConvert: KtTabView.(view: View, i: Int, bean: Any) -> Unit)
    {
        this.itemConvert = itemConvert
    }

    var datas: List<Any>? = null

    var index: Int? = null
    var tabWidth: Any = MATCH_PARENT
    var isScroll: Boolean = false
    var scrollOffset: Double? = null
    var lineBg: Any? = null
    var lineBgRes: Int? = null
    var lineHeight: Any = 2
    var linePaddingH: Any = 8
    var lineTransZ: Any = -0.1
    var lineGravity: Int = Gravity.BOTTOM
    var lineLen: Any = 24
    var isAuto = false
    var isWorm = false
    var isSmooth: Boolean? = null

    var viewPagerId: String? = null

    open fun initUI(context: Context, view: KtTabView)
    {
        super.initUI(context, view)

        if (isScroll) tabWidth = WRAP_CONTENT
        view.initScrollOrContent(isScroll)
        view.initTabLayout(tabWidth.dist)

        scrollOffset?.let { view.scrollOffset = it }

        divider?.let {
            if (it is UiShape)
            {
                view.tabLayout.dividerDrawable = it.createDrawable()
            } else
            {
                divider.toString().preLoadCallback(context) { drawable -> view.tabLayout.dividerDrawable = drawable }
            }
            view.tabLayout.showDividers = showDividers ?: LinearLayout.SHOW_DIVIDER_MIDDLE
        }

        onItemSelect?.let { view.onItemSelect = it }

        index?.let { view.index = it }

        fun initLine()
        {
            view.linePaddingH = linePaddingH.dist
            view.lineLen = lineLen.dist
            view.lineTransZ = lineTransZ.distFloat
            view.lineGravity = lineGravity
            view.isAuto = isAuto
            view.isWorm = isWorm
            view.initTabLine(lineHeight.dist)
        }
        lineBg?.let {
            initLine()
            view.tabLine?.let()
            { line ->
                if (it is UiShape)
                {
                    line.background = it.createDrawable()
                } else if (it is Int)
                {
                    line.setBackgroundColor(it)
                } else
                {
                    line.bg = it.toString()
                }
            }
        }
        lineBgRes?.let {
            initLine()
            view.tabLine?.setBackgroundResource(it)
        }

        isSmooth?.let { view.isSmooth = it }

        // 模板布局
        if (itemConvert != null)
        {
            if (childs.isNotEmpty() && !datas.isNullOrEmpty())
            {
                view.itemUI = childs[0]
                itemConvert?.let { itemConvert -> view.setItemConvert { v, i, bean -> view.itemConvert(v, i, bean) } }
                view.datas = datas!!
            }
        }
        // 固定布局
        else
        {
            // 递归子元素
            childs.forEach()
            {
                if (!isScroll)
                {
                    it.width = it.width ?: 0
                }
                it.height = it.height ?: MATCH_PARENT
                it.createView(context, view.tabLayout)
            }
            view.initTabViews()
        }
    }

    /** 创建view */
    override fun createView(context: Context, parent: ViewGroup?): View
    {
        val view = KtTabView(context)
        initUI(context, view)
        // viewPager
        viewPagerId?.let()
        { id ->
            ktDelay()
            {
                if (parent != null)
                {
                    var v: KtViewPager = try
                    {
                        parent.findView<KtViewPager>(id)
                    } catch (e: Exception)
                    {
                        (parent.parent as ViewGroup).findView<KtViewPager>(id)
                    }

                    view.viewPager = v
                }
            }
        }
        addToParent(parent, view)
        return view
    }

    fun createTabView(context: Context, parent: ViewGroup?): KtTabView = createView(context, parent) as KtTabView
}

fun Any.ui_Tab(id: String? = null, block: (UiTab.() -> Unit)? = null): UiTab
{
    val ui = UiTab(id)
    block?.let { ui.it() }
    if (this is UiGroup) addChild(ui)
    return ui
}

open class KtTabView : FrameLayout, View.OnClickListener
{
    constructor(context: Context) : super(context)
    {
        initXML()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtTabView))
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtTabView, defStyleAttr, 0))
    }

    private fun initXML(typedArray: TypedArray? = null)
    {
//        isFillViewport = true
//        scrollBarSize = 0
        content = FrameLayout(context)
//        addView(content, MATCH_PARENT, MATCH_PARENT)

        typedArray?.let()
        {
            var tabWidth = it.getDimensionPixelOffset(R.styleable.KtTabView_kt_tabWidth, MATCH_PARENT)

            isScroll = it.getBoolean(R.styleable.KtTabView_kt_isScroll, isScroll)
            if (isScroll)
            {
                tabWidth = WRAP_CONTENT
            }
            initScrollOrContent(isScroll)
            initTabLayout(tabWidth)

            scrollOffset = it.getFloat(R.styleable.KtTabView_kt_scrollOffset, scrollOffset.toFloat()).toDouble()

            if (it.hasValue(R.styleable.KtTabView_kt_divider))
            {
                tabLayout.dividerDrawable = it.getDrawable(R.styleable.KtTabView_kt_divider)
                tabLayout.showDividers = it.getInt(R.styleable.KtTabView_kt_showDividers, LinearLayout.SHOW_DIVIDER_MIDDLE)
            }

            index = it.getInt(R.styleable.KtTabView_kt_index, index)

            if (it.hasValue(R.styleable.KtTabView_kt_lineBg))
            {
                linePaddingH = it.getDimensionPixelOffset(R.styleable.KtTabView_kt_linePaddingH, ktPx(8.0))
                lineLen = it.getDimensionPixelOffset(R.styleable.KtTabView_kt_lineLen, ktPx(24.0))
                lineTransZ = it.getDimension(R.styleable.KtTabView_kt_lineTransZ, -0.1f)
                lineGravity = it.getInt(R.styleable.KtTabView_kt_lineGravity, Gravity.BOTTOM)
                isAuto = it.getBoolean(R.styleable.KtTabView_kt_isAuto, isAuto)
                isWorm = it.getBoolean(R.styleable.KtTabView_kt_isWorm, isWorm)
                initTabLine(it.getDimensionPixelOffset(R.styleable.KtTabView_kt_lineHeight, ktPx(2.0)))
                tabLine?.background = it.getDrawable(R.styleable.KtTabView_kt_lineBg)
            }

            isSmooth = it.getBoolean(R.styleable.KtTabView_kt_isSmooth, isSmooth)

            if (it.hasValue(R.styleable.KtTabView_kt_viewPagerId))
            {
                val viewPagerId = it.getResourceIdOrThrow(R.styleable.KtTabView_kt_viewPagerId)
                post()
                {
                    val p = parent
                    if (p is ViewGroup)
                    {
                        viewPager = p.findViewById<KtViewPager>(viewPagerId)
                        if (viewPager == null) ktSafe { viewPager = (p.parent as ViewGroup).findViewById<KtViewPager>(viewPagerId) }
                        resetLinePosition()
                    }
                }
            }

            it.recycle()
        }
//        tabLine = View(context)
//        tabLine?.setBackgroundColor(KtColor.main)
//        addView(tabLine, MATCH_PARENT, px(2.0))
//        lineParams = tabLine?.layoutParams as LayoutParams?
    }

    private var isScroll = false

    internal fun initScrollOrContent(isScroll: Boolean)
    {
        if (isScroll)
        {
            scrollView = HorizontalScrollView(context)
            scrollView?.addView(content, WRAP_CONTENT, MATCH_PARENT)
            addView(scrollView, WRAP_CONTENT, MATCH_PARENT)
        } else
        {
            addView(content, MATCH_PARENT, MATCH_PARENT)
        }
    }

    internal fun initTabLayout(w: Int)
    {
        tabLayout = LinearLayout(context)
        tabLayout.orientation = HORIZONTAL
        content.addView(tabLayout, w, MATCH_PARENT)
    }

    internal fun initTabLine(h: Int)
    {
        tabLine = View(context)
        content.addView(tabLine, MATCH_PARENT, h)
        tabLine?.translationZ = lineTransZ
        lineParams = tabLine?.layoutParams as LayoutParams?
        lineParams?.gravity = lineGravity
        resetLinePosition()
    }

    var itemUI: UiView? = ui_Text()
    {
        width = 0
        height = MATCH_PARENT
        weight = 1.0
        textSize = 14
        gravity = Gravity.CENTER
    }
        set(value)
        {
            if (!isScroll)
            {
                if (value?.width == null)
                {
                    value?.width = 0
                    value?.weight = 1.0
                }
            }
            value?.height = value?.height ?: MATCH_PARENT
            field = value
        }

    internal var itemConvert: ((view: View, i: Int, bean: Any) -> Unit)? = { view, i, bean ->
        view as KtTextView
        bean as String
        view.text = bean
    }

    fun setItemConvert(itemConvert: (view: View, i: Int, bean: Any) -> Unit)
    {
        this.itemConvert = itemConvert
    }

    var datas: List<Any> = ArrayList()
        set(value)
        {
            field = value
            tabLayout.removeAllViews()
            if (itemUI != null) value.forEachIndexed()
            { index, any ->

                val v = itemUI!!.createView(context, tabLayout)
                itemConvert?.invoke(v, index, any)
            }
            initTabViews()
            resetLinePosition()
        }

    private var scrollView: HorizontalScrollView? = null

    lateinit var content: FrameLayout
        private set
    lateinit var tabLayout: LinearLayout
        internal set
    var tabLine: View? = null
        internal set
    var viewPager: ViewPager? = null
        set(value)
        {
            field = value
            value?.setCurrentItem(index, false)
            value?.addOnPageChangeListener(object : ViewPager.OnPageChangeListener
            {
                override fun onPageSelected(index: Int)
                {
                    selectTab(index)
                    this@KtTabView.index = index

                }

                override fun onPageScrolled(i: Int, scale: Float, arg2: Int)
                {
                    onScrolled(i, scale)
                }

                override fun onPageScrollStateChanged(arg0: Int)
                {
                }
            })
        }

    var scrollOffset: Double = 0.3

    /** line水平padding  */
    internal var linePaddingH = 0

    internal var lineLen = 0

    internal var lineTransZ = 0f

    internal var lineGravity: Int = Gravity.BOTTOM

    var isSmooth = true

    var isAuto = false

    var isWorm = false

    private var lineX = 0f

    private var lineW = 0f

    private var lineParams: LayoutParams? = null

    val list: ArrayList<View> = ArrayList()

    internal var onItemSelect: (KtTabView.(childView: View, isSelect: Boolean, i: Int, bean: Any) -> Unit)? = null
    fun setOnItemSelect(onItemSelect: (view: View, isSelect: Boolean, i: Int, bean: Any) -> Unit)
    {
        this.onItemSelect = { view, isSelect, i, bean -> onItemSelect(view, isSelect, i, bean) }
    }

    internal var onItemIntercept: (KtTabView.(childView: View, i: Int, bean: Any) -> Boolean)? = null
    fun setOnItemIntercept(onItemIntercept: (view: View, i: Int, bean: Any) -> Boolean)
    {
        this.onItemIntercept = { view, i, bean -> onItemIntercept(view, i, bean) }
    }

    fun initTabViews()
    {
        list.clear()
        tabLayout.forEach()
        { view ->
            addChild(view)
        }
        select(index)
    }

    private fun addChild(view: View)
    {
        list.add(view)
        view.setOnClickListener(this)
    }

    /** 当前选项下标 */
    var index = 0
        internal set

    override fun onClick(view: View)
    {
        var selectIndex = 0
        list.forEachIndexed()
        { i, v ->
            if(v == view) selectIndex = i
        }

        select(selectIndex)
    }

    fun select(i: Int)
    {
        if (onItemIntercept?.invoke(this, list[i], i, datas[i]) == true)
        {
            return
        }
        selectTab(i)
        viewPager?.setCurrentItem(i, isSmooth)
    }

    private fun selectTab(index: Int)
    {
        this.index = index
        list.forEachIndexed()
        { i, v ->
            onItemSelect?.let { this.it(v, index == i, i, datas[i]) }
        }
    }

    /**
     * tab切换滚动
     */
    open fun onScrolled(i: Int, scale: Float)
    {
        try
        {
            val nowView = list[i]
            val nextWidth = if (i < list.size - 1)
            {
                list[i + 1].width
            } else
            {
                nowView.width
            }
            // 蠕虫
            if (isWorm)
            {
                if (isAuto)
                {
                    if (scale < 0.5)
                    {
                        lineX = nowView.x
                        lineW = nowView.width + nextWidth * scale * 2
                    } else
                    {
                        val nW = nowView.width * (scale - 0.5f) * 2
                        lineX = nowView.x + nW
                        lineW = nowView.width + nextWidth - nW
                    }
                } else
                {
                    if (scale < 0.5)
                    {
                        lineX = nowView.x + (nowView.width - lineLen) / 2f
                        lineW = lineLen + (nextWidth + nowView.width) * scale
                    } else
                    {
                        lineX = nowView.x + (nowView.width - lineLen) / 2f + (nextWidth + nowView.width) * (scale - 0.5f)
                        lineW = lineLen + (nextWidth + nowView.width) * (1 - scale)
                    }
                }
            } else
            {
                if (isAuto)
                {
                    lineX = nowView.x + nowView.width * scale
                    lineW = nowView.width + (nextWidth - nowView.width) * scale
                } else
                {
                    lineX = nowView.x + (nowView.width - lineW) / 2 + (nextWidth + nowView.width) / 2f * scale
                    lineW = lineLen.toFloat()
                }
            }
        } catch (e: Exception)
        {
        }

        updateLine()
    }

    /**
     * 重置滑动位置
     */
    fun resetLinePosition()
    {
        post { onScrolled(index, 0f) }
    }

    /**
     * 设置滑动位置
     */
    private fun updateLine()
    {
        val x: Float
        val w: Float
        if (isAuto)
        {
            x = lineX + linePaddingH + 1
            w = lineW - linePaddingH * 2
        } else
        {
            x = lineX + 2
            w = lineW
        }

        lineParams?.setMargins(x.toInt(), 0, 0, 0)
        lineParams?.width = w.toInt()
        tabLine?.layoutParams = lineParams

        scrollView?.let()
        {
            // 滑动scrollview
            val min = width * scrollOffset

            val sx = (lineX - 2 - (width - lineW) / 2).toInt()

            if (scrollX - sx > min)
            {
                it.smoothScrollTo((sx + min).toInt(), 0)
            }
            if (scrollX - sx < -min)
            {
                it.smoothScrollTo((sx - min).toInt(), 0)
            }
        }
    }
}